package user

import (
	"context"
	"fmt"
	"github.com/zeromicro/go-zero/core/fx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go-admin/base/dao"
	"go-admin/base/utils"

	"go-admin/base/internal/svc"
	"go-admin/base/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type EditRolesLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewEditRolesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditRolesLogic {
	return &EditRolesLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *EditRolesLogic) EditRoles(req *types.UserRoleReqDTO) (resp *types.UserBooleanRespDTOS, err error) {
	userRoles, err := l.svcCtx.UserRoleModel.FindUserRolesByUserIds(l.ctx, []int64{req.UserID})
	if err != nil {
		fmt.Errorf(err.Error())
		return nil, err
	}
	roleIdsDB := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, userRole := range userRoles {
			source <- userRole
		}
	}).Map(func(item any) any {
		iu := item.(*dao.UserRole)
		return iu.RoleId
	}))

	roleIds := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, role := range req.Roles {
			source <- role
		}
	}).Filter(func(item any) bool {
		iu := item.(types.RoleRespDTO)
		// todo int64如何判断非空
		return iu.UserRoleID != 0
	}).Map(func(item any) any {
		iu := item.(types.RoleRespDTO)
		return iu.RoleID
	}))

	addRoleIds := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, role := range req.Roles {
			source <- role
		}
	}).Filter(func(item any) bool {
		iu := item.(types.RoleRespDTO)
		// todo int64如何判断非空
		return iu.UserRoleID == 0
	}).Map(func(item any) any {
		iu := item.(types.RoleRespDTO)
		return iu.RoleID
	}))

	delRoleIds := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, roleId := range roleIdsDB {
			source <- roleId
		}
	}).Filter(func(item any) bool {
		roleIdDB := item.(int64)
		return !utils.IsContain[int64](roleIds, roleIdDB)
	}))

	err = l.svcCtx.Conn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		if len(delRoleIds) > 0 {
			collector := utils.Collector[int64](fx.From(func(source chan<- any) {
				for _, userRole := range userRoles {
					source <- userRole
				}
			}).Filter(func(item any) bool {
				userRole := item.(*dao.UserRole)
				if userRole.UserId != req.UserID {
					return false
				}
				return utils.IsContain[int64](delRoleIds, userRole.RoleId)
			}))
			err := l.svcCtx.UserRoleModel.DeleteByIdsSession(l.ctx, session, collector)
			if err != nil {
				fmt.Errorf(err.Error())
				return err
			}
		}

		if len(addRoleIds) > 0 {
			var userRolesAdd []*dao.UserRole
			for _, roleId := range addRoleIds {
				userRole := &dao.UserRole{
					UserId: req.UserID,
					RoleId: roleId,
				}
				userRolesAdd = append(userRolesAdd, userRole)
			}
			err2 := l.svcCtx.UserRoleModel.BatchInsert(l.ctx, sqlx.NewSqlConnFromSession(session), userRolesAdd)
			if err2 != nil {
				return err2
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return &types.UserBooleanRespDTOS{
		Data: true,
		Result: types.Result{
			Code: 200,
		},
	}, nil
}
